home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / Newswatcher 2.0b22 / NW Source / Source / send.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-04  |  15.5 KB  |  662 lines  |  [TEXT/MMCC]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     send.c
  4.  
  5.     This module handles sending postings and mail messages.
  6.     
  7.     Copyright © 1994, Northwestern University.
  8.  
  9. ----------------------------------------------------------------------------*/
  10.  
  11. #include <string.h>
  12.  
  13. #include "glob.h"
  14. #include "dialog.h"
  15. #include "news.h"
  16. #include "send.h"
  17. #include "smtp.h"
  18. #include "header.h"
  19. #include "newswatcher.h"
  20. #include "status.h"
  21. #include "message.h"
  22. #include "charset.h"
  23. #include "cancel.h"
  24. #include "memutil.h"
  25. #include "strutil.h"
  26. #include "ic.h"
  27.  
  28.  
  29.  
  30. #define kPostAlert            135            /* Post confirm dialog */
  31. #define kPostCancelAlert    147            /* Post cancel dialog */
  32.  
  33.  
  34.  
  35. /*----------------------------------------------------------------------------
  36.     Wrap 
  37.     
  38.     Wraps paragraphs to lines of at most 74 characters long.
  39.             
  40.     Entry:    text = handle to text to be wrapped.
  41.             start = offset in text of beginning of text to be wrapped.
  42.             end = offset in text of end of text to be wrapped.
  43.  
  44.      Only lines which which exceed 80 characters in length are wrapped.
  45. ----------------------------------------------------------------------------*/
  46.  
  47. void Wrap (Handle text, long start, long end)
  48. {
  49.     char *p, *pEnd, *q, *lastSpace;
  50.     
  51.     p = *text + start;
  52.     pEnd = *text + end;
  53.     while (p < pEnd) {
  54.         q = p;
  55.         while (q < pEnd && *q != CR) q++;
  56.         if (q - p > 80) {
  57.             q = p;
  58.             lastSpace = 0;
  59.             while (true) {
  60.                 while (q < pEnd && *q != ' ' && *q != CR) q++;
  61.                 if (q < pEnd && *q == ' ') {
  62.                     while (q < pEnd && *q == ' ') q++;
  63.                     q--;
  64.                 }
  65.                 if (q - p >= 75 && lastSpace != 0) {
  66.                     *lastSpace = CR;
  67.                     p = lastSpace + 1;
  68.                     lastSpace = 0;
  69.                 }
  70.                 if (q >= pEnd || *q == CR) break;
  71.                 lastSpace = q;
  72.                 q++;
  73.             }
  74.         }
  75.         p = q+1;
  76.     }
  77. }
  78.  
  79.  
  80.  
  81. /*----------------------------------------------------------------------------
  82.     UnWrap 
  83.     
  84.     Unwraps paragraphs.
  85.             
  86.     Entry:    text = handle to text to be unwrapped.
  87.             start = offset in text of beginning of text to be unwrapped.
  88.             end = offset in text of end of text to be unwrapped.
  89. ----------------------------------------------------------------------------*/
  90.  
  91. void UnWrap (Handle text, long start, long end)
  92. {
  93.     char *p, *pEnd;
  94.     
  95.     p = *text + start;
  96.     pEnd = *text + end;
  97.     while (p < pEnd) {
  98.         while (p < pEnd && *p != CR) p++;
  99.         p++;
  100.         if (p < pEnd) {
  101.             if (*p == ' ' || *p == '\t') continue;
  102.             if (*p == CR) {
  103.                 while (p < pEnd && *p == CR) p++;
  104.                 continue;
  105.             }
  106.             *(p-1) = ' ';
  107.         }
  108.     }
  109. }
  110.  
  111.  
  112.  
  113. /*----------------------------------------------------------------------------
  114.     GetRecipients 
  115.     
  116.     Gets recipient addresses for an email message.
  117.             
  118.     Entry:    text = message to be mailed, including headers.
  119.             hdr = C-format message header to process (To, Cc, or Bcc).
  120.             
  121.     Exit:    function result = error code.
  122.             *recipients = handle to comma-separated list of
  123.                 recipient email addresses, or nil if header not found.
  124. ----------------------------------------------------------------------------*/
  125.  
  126. static OSErr GetRecipients (Handle text, char *hdr, Handle *recipients)
  127. {
  128.     Handle recip;
  129.     OSErr err = noErr;
  130.     char *p, *pEnd, *q, *r, *begin, *end;
  131.     long len;
  132.     short parenLevel;
  133.     Boolean insideQuotedString = false;
  134.     
  135.     err = FindHeaderHandle(text, hdr, &recip);
  136.     if (err != noErr) return err;
  137.     if (recip == nil) {
  138.         *recipients = nil;
  139.         return noErr;
  140.     }
  141.     
  142.     /* Strip comments in parentheses and blanks. */
  143.     
  144.     p = q = *recip;
  145.     len = MyGetHandleSize(recip);
  146.     pEnd = p + len;
  147.     while (p < pEnd) {
  148.         if (*p == '(') {
  149.             parenLevel = 1;
  150.             p++;
  151.             while (p < pEnd && parenLevel > 0) {
  152.                 if (*p == '(') {
  153.                     parenLevel++;
  154.                 } else if (*p == ')') {
  155.                     parenLevel--;
  156.                 }
  157.                 p++;
  158.             }
  159.         } else if (*p == ' ') {
  160.             p++;
  161.         } else {
  162.             *q++ = *p++;
  163.         }
  164.     }
  165.     len = q - *recip;
  166.     
  167.     /* Extract recipients */
  168.     
  169.     p = q = *recip;
  170.     pEnd = p + len;
  171.     while (p < pEnd) {
  172.         r = p;
  173.         while (r < pEnd) {
  174.             if (*r == '"') {
  175.                 insideQuotedString = true;
  176.                 r++;
  177.                 while (r < pEnd && *r != '"') r++;
  178.                 if (r >= pEnd) break;
  179.                 insideQuotedString = false;
  180.                 r++;
  181.             } else if (*r == '<' || *r == ',') {
  182.                 break;
  183.             } else {
  184.                 r++;
  185.             }
  186.         }
  187.         if (insideQuotedString) break;
  188.         if (r >= pEnd || *r == ',') {
  189.             begin = p;
  190.             end = r-1;
  191.         } else {
  192.             r++;
  193.             begin = r;
  194.             while (r < pEnd && *r != '>') r++;
  195.             end = r-1;
  196.         } 
  197.         p = r;
  198.         while (p < pEnd && *p != ',') p++;
  199.         if (*p == ',') p++;
  200.         len = end - begin + 1;
  201.         if (q != *recip) *q++ = ',';
  202.         BlockMoveData(begin, q, len);
  203.         q += len;
  204.     }
  205.     len = q - *recip;
  206.     MySetHandleSize(recip, len);
  207.     *recipients = recip;
  208.     return noErr;
  209. }
  210.  
  211.  
  212.  
  213. /*----------------------------------------------------------------------------
  214.     SendMailMessage 
  215.     
  216.     Send a mail message.
  217.             
  218.     Entry:    text = message to be mailed, including headers.
  219.             
  220.     Exit:    function result = error code.
  221. ----------------------------------------------------------------------------*/
  222.  
  223. static OSErr SendMailMessage (Handle text)
  224. {
  225.     SmtpStreamHandle s;
  226.     SmtpErr smtpErr;
  227.     CStr255 cmd;
  228.     long num;
  229.     CStr255 msg;
  230.     OSErr err = noErr;
  231.     Handle to = nil;
  232.     Handle cc = nil;
  233.     Handle bcc = nil;
  234.     long toLen, ccLen, bccLen, len;
  235.     char *q;
  236.     
  237.     MyICReadSharedPrefs(kICEmail);
  238.     MyICReadSharedPrefs(kICSMTPHost);
  239.     
  240.     err = GetRecipients(text, "To", &to);
  241.     if (err != noErr) goto exit1;
  242.     err = GetRecipients(text, "Cc", &cc);
  243.     if (err != noErr) goto exit1;
  244.     err = GetRecipients(text, "Bcc", &bcc);
  245.     if (err != noErr) goto exit1;
  246.     
  247.     toLen = to == nil ? 0 : MyGetHandleSize(to);
  248.     ccLen = cc == nil ? 0 : MyGetHandleSize(cc);
  249.     bccLen = bcc == nil ? 0 : MyGetHandleSize(bcc);
  250.     
  251.     len = toLen;
  252.     if (cc != nil) {
  253.         if (len > 0) len++;
  254.         len += ccLen;
  255.     }
  256.     if (bcc != nil) {
  257.         if (len > 0) len++;
  258.         len += bccLen;
  259.     }
  260.     len++;
  261.     
  262.     if (to == nil) {
  263.         err = MyNewHandle(len, &to);
  264.     } else {
  265.         err = MySetHandleSize(to, len);
  266.     }
  267.     if (err != noErr) goto exit1;
  268.     
  269.     q = *to + toLen;
  270.     if (cc != nil) {
  271.         if (q > *to) *q++ = ',';
  272.         BlockMoveData(*cc, q, ccLen);
  273.         q += ccLen;
  274.     }
  275.     if (bcc != nil) {
  276.         if (q > *to) *q++ = ',';
  277.         BlockMoveData(*bcc, q, bccLen);
  278.         q += bccLen;
  279.     }
  280.     *q = 0;
  281.     
  282.     p2cstr(gPrefs.mailServerName);
  283.     smtpErr = SmtpOpen((char*)gPrefs.mailServerName, &s);
  284.     c2pstr((char*)gPrefs.mailServerName);
  285.     if (smtpErr != smtpNoErr) goto exit2;
  286.     
  287.     MyHLock(to);
  288.     smtpErr = SmtpSendMessage(s, gPrefs.emailAddress, *to, text);
  289.     MyHUnlock(to);
  290.     if (smtpErr != smtpNoErr) goto exit2;
  291.     
  292.     smtpErr = SmtpClose(s);
  293.     if (smtpErr != smtpNoErr) goto exit2;
  294.     
  295.     MyDisposeHandle(to);
  296.     MyDisposeHandle(cc);
  297.     MyDisposeHandle(bcc);
  298.     
  299.     return noErr;
  300.     
  301. exit1:
  302.     
  303.     MyDisposeHandle(to);
  304.     MyDisposeHandle(cc);
  305.     MyDisposeHandle(bcc);
  306.     return err;
  307.     
  308. exit2:
  309.     
  310.     MyDisposeHandle(to);
  311.     MyDisposeHandle(cc);
  312.     MyDisposeHandle(bcc);
  313.     if (smtpErr == smtpServerErr) {
  314.         if (s != nil) SmtpClose(s);
  315.         SmtpGetServerErrInfo(cmd, &num, msg);
  316.         err = ServerErrorMessage(kStrMail, cmd, msg);
  317.         if (err != noErr) return err;
  318.         return userCanceledErr;
  319.     } else {
  320.         return SmtpGetOSErr();
  321.     }
  322. }
  323.  
  324.  
  325.  
  326. /*----------------------------------------------------------------------------
  327.     AreYouSure 
  328.     
  329.     Present "Are you sure you want to post" alert.
  330.             
  331.     Exit:    function result = error code.
  332. ----------------------------------------------------------------------------*/
  333.  
  334. static OSErr AreYouSure (void)
  335. {
  336.     DialogPtr dlg = nil;
  337.     short item;
  338.     OSErr err = noErr;
  339.  
  340.     if (!gPrefs.areYouSureAlert) return noErr;
  341.     err = MyGetNewDialog(kPostAlert, ok, cancel, &dlg);
  342.     if (err != noErr) return err;
  343.     SysBeep(0);
  344.     MyModalDialog(dlg, gDialogFilterUPP, &item);
  345.     err = DoClose(dlg);
  346.     if (err != noErr) return err;
  347.     return item == ok ? noErr : userCanceledErr;
  348. }
  349.  
  350.  
  351.  
  352. /*----------------------------------------------------------------------------
  353.     BuildMessageForPrinting 
  354.     
  355.     Build a message for printing.
  356.             
  357.     Entry:    wind = pointer to message window.
  358.             
  359.     Exit:    function result = error code.
  360.             *messageText = handle to message text to be printed.
  361. ----------------------------------------------------------------------------*/
  362.  
  363. OSErr BuildMessageForPrinting (WindowPtr wind, Handle *messageText)
  364. {
  365.     TWindow **info;
  366.     TEHandle theTE;
  367.     Handle text = nil;
  368.     Handle msg = nil;
  369.     Handle newsgroups, to, subject, cc, bcc, replyto;
  370.     Handle followupto, keywords, distribution;
  371.     Handle extraMail, signature, references;
  372.     OSErr err = noErr, err1 = noErr;
  373.     long sigLen, textLen, newTextLen;
  374.     char *q;
  375.     Boolean newsIcon, mailIcon, selfIcon;
  376.  
  377.     info = (TWindow**)GetWRefCon(wind);
  378.     theTE = (**info).theTE;
  379.     text = (**theTE).hText;
  380.     newsgroups = (**(**info).newsgroupsField).hText;
  381.     to = (**(**info).toField).hText;
  382.     subject = (**(**info).subjectField).hText;
  383.     cc = (**(**info).ccField).hText;
  384.     bcc = (**(**info).bccField).hText;
  385.     replyto = (**(**info).replytoField).hText;
  386.     followupto = (**(**info).followuptoField).hText;
  387.     keywords = (**(**info).keywordsField).hText;
  388.     distribution = (**(**info).distributionField).hText;
  389.     extraMail = (**(**info).extraMailField).hText;
  390.     signature = (**(**info).signatureField).hText;
  391.     references = (**info).references;
  392.     newsIcon = (**info).newsIcon;
  393.     mailIcon = (**info).mailIcon;
  394.     selfIcon = (**info).selfIcon;
  395.     
  396.     err = MyHandToHand(&text);
  397.     if (err != noErr) return err;
  398.     
  399.     textLen = MyGetHandleSize(text);
  400.     q = *text + textLen - 1;
  401.     while (q > *text && isLWSPorCR(*q)) q--;
  402.     q++;
  403.     newTextLen = q - *text;
  404.     if (newTextLen != textLen) {
  405.         textLen = newTextLen;
  406.         MySetHandleSize(text, textLen);
  407.     }
  408.  
  409.     sigLen = MyGetHandleSize(signature);
  410.     if (sigLen > 0) {
  411.         newTextLen = textLen + sigLen + 1;
  412.         err = MySetHandleSize(text, newTextLen);
  413.         if (err != noErr) goto exit;
  414.         q = *text + textLen;
  415.         *q++ = CR;
  416.         BlockMoveData(*signature, q, sigLen);
  417.         textLen = newTextLen;
  418.     }
  419.     
  420.     if (textLen == 0) {
  421.         textLen = 1;
  422.         err = MySetHandleSize(text, textLen);
  423.         if (err != noErr) goto exit;
  424.         **text = ' ';
  425.     }
  426.     
  427.     if (!mailIcon) to = cc = bcc = nil;
  428.     if (!newsIcon) newsgroups = followupto = distribution = nil;
  429.     err = MakeMailHeader(subject, to, cc, bcc, (**info).from,
  430.         (**info).selfIcon, replyto, keywords, extraMail,
  431.         newsgroups, followupto, distribution,
  432.         references, &msg);
  433.     if (err != noErr) goto exit;
  434.     err = MyHandAndHand(text, msg);
  435.     if (err != noErr) goto exit;
  436.     
  437.     *messageText = msg;
  438.     MyDisposeHandle(text);
  439.     return noErr;
  440.     
  441. exit:
  442.  
  443.     MyDisposeHandle(text);
  444.     MyDisposeHandle(msg);
  445.     return err;
  446. }
  447.  
  448.  
  449.  
  450. /*----------------------------------------------------------------------------
  451.     SendMessage 
  452.     
  453.     Send a message.
  454.             
  455.     Entry:    wind = pointer to message window.
  456.             
  457.     Exit:    function result = error code.
  458. ----------------------------------------------------------------------------*/
  459.  
  460. OSErr SendMessage (WindowPtr wind)
  461. {
  462.     TWindow **info;
  463.     TEHandle theTE;
  464.     Handle text = nil;
  465.     Handle msg = nil;
  466.     Handle newsgroups, to, subject, cc, bcc, replyto;
  467.     Handle followupto, keywords, distribution;
  468.     Handle extraNews, extraMail, signature, references;
  469.     OSErr err = noErr, err1 = noErr;
  470.     long sigLen, textLen, newTextLen;
  471.     char *q;
  472.     Boolean newsIcon, mailIcon, selfIcon;
  473.     short item;
  474.     CStr255 idStr;
  475.     CStr255 statusMsg;
  476.     FSSpec fSpec;
  477.     Boolean wasChanged;
  478.     Boolean posted = false, postIndeterminate = false, mailStarted = false;
  479.     DialogPtr dlg = nil;
  480.  
  481.     info = (TWindow**)GetWRefCon(wind);
  482.     theTE = (**info).theTE;
  483.     text = (**theTE).hText;
  484.     newsgroups = (**(**info).newsgroupsField).hText;
  485.     to = (**(**info).toField).hText;
  486.     subject = (**(**info).subjectField).hText;
  487.     cc = (**(**info).ccField).hText;
  488.     bcc = (**(**info).bccField).hText;
  489.     replyto = (**(**info).replytoField).hText;
  490.     followupto = (**(**info).followuptoField).hText;
  491.     keywords = (**(**info).keywordsField).hText;
  492.     distribution = (**(**info).distributionField).hText;
  493.     extraNews = (**(**info).extraNewsField).hText;
  494.     extraMail = (**(**info).extraMailField).hText;
  495.     signature = (**(**info).signatureField).hText;
  496.     references = (**info).references;
  497.     newsIcon = (**info).newsIcon;
  498.     mailIcon = (**info).mailIcon;
  499.     selfIcon = (**info).selfIcon;
  500.     
  501.     if (!newsIcon && !mailIcon && !selfIcon) {
  502.         ErrorMessageNumber(kStrMustCheckAnIcon);
  503.         return userCanceledErr;
  504.     }
  505.     
  506.     if (HeaderLineIsEmpty(subject)) {
  507.         ErrorMessageNumber(kStrMustSupplySubject);
  508.         return userCanceledErr;
  509.     }
  510.     
  511.     if (newsIcon && HeaderLineIsEmpty(newsgroups)) {
  512.         ErrorMessageNumber(kStrMustSupplyNewsgroup);
  513.         return userCanceledErr;
  514.     }
  515.     
  516.     if (mailIcon && !selfIcon && 
  517.         HeaderLineIsEmpty(to) && HeaderLineIsEmpty(cc) && HeaderLineIsEmpty(bcc)) 
  518.     {
  519.         ErrorMessageNumber(kStrMustSupplyRecipient);
  520.         return userCanceledErr;
  521.     }
  522.     
  523.     if (newsIcon) {
  524.         err = AreYouSure();
  525.         if (err != noErr) return err;
  526.     }
  527.     
  528.     err = MyHandToHand(&text);
  529.     if (err != noErr) return err;
  530.     
  531.     textLen = MyGetHandleSize(text);
  532.     q = *text + textLen - 1;
  533.     while (q > *text && isLWSPorCR(*q)) q--;
  534.     q++;
  535.     newTextLen = q - *text;
  536.     if (newTextLen != textLen) {
  537.         textLen = newTextLen;
  538.         MySetHandleSize(text, textLen);
  539.     }
  540.     
  541.     if ((**info).wrapOnSend) Wrap(text, 0, textLen);
  542.  
  543.     sigLen = MyGetHandleSize(signature);
  544.     if (sigLen > 0) {
  545.         newTextLen = textLen + sigLen + 1;
  546.         err = MySetHandleSize(text, newTextLen);
  547.         if (err != noErr) goto exit;
  548.         q = *text + textLen;
  549.         *q++ = CR;
  550.         BlockMoveData(*signature, q, sigLen);
  551.         textLen = newTextLen;
  552.     }
  553.     
  554.     if (textLen == 0) {
  555.         textLen = 1;
  556.         err = MySetHandleSize(text, textLen);
  557.         if (err != noErr) goto exit;
  558.         **text = ' ';
  559.     }
  560.     
  561.     if (newsIcon) {
  562.         GetCString(kStrPostingMessageStatusMsg, statusMsg);
  563.         err = DisplayStatusMessage(statusMsg);
  564.         if (err != noErr) goto exit;
  565.         err = MakeNewsHeader(newsgroups, subject, replyto, 
  566.             followupto, keywords, distribution, extraNews,
  567.             nil, references, &msg);
  568.         if (err != noErr) goto exit;
  569.         FindHeaderCString(msg, "Message-ID", idStr, sizeof(idStr));
  570.         err = MyHandAndHand(text, msg);
  571.         if (err != noErr) goto exit;
  572.         MapMacToLatin1Handle(msg);
  573.         err = PostArticle(msg, statusMsg, &postIndeterminate);
  574.         posted = err == noErr || postIndeterminate;
  575.         if (err != noErr) goto exit;
  576.         MyDisposeHandle(msg);
  577.         msg = nil;
  578.     }
  579.     
  580.     if (mailIcon || selfIcon) {
  581.         mailStarted = true;
  582.         err = DisplayStatusMessageNumber(kStrMailingMessageStatusMsg);
  583.         if (err != noErr) goto exit;
  584.         if (!mailIcon) to = cc = bcc = nil;
  585.         if (!newsIcon) newsgroups = followupto = distribution = nil;
  586.         err = MakeMailHeader(subject, to, cc, bcc, (**info).from,
  587.             (**info).selfIcon, replyto, keywords, extraMail,
  588.             newsgroups, followupto, distribution,
  589.             references, &msg);
  590.         if (err != noErr) goto exit;
  591.         err = MyHandAndHand(text, msg);
  592.         if (err != noErr) goto exit;
  593.         MapMacToLatin1Handle(msg);
  594.         err = SendMailMessage(msg);
  595.         if (err != noErr) goto exit;
  596.     }
  597.  
  598.     (**info).changed = false;
  599.     MyDisposeHandle(text);
  600.     MyDisposeHandle(msg);
  601.     
  602.     if ((**info).alias != nil && gPrefs.savedMsgDelAfterSend) {
  603.         err = ResolveAlias(nil, (**info).alias, &fSpec, &wasChanged);
  604.         if (err == noErr) {
  605.             (**info).alias = nil;
  606.             err = FSpDelete(&fSpec);
  607.             if (err != noErr) return err;
  608.         }
  609.     }
  610.     
  611.     return noErr;
  612.     
  613. exit:
  614.  
  615.     MyDisposeHandle(text);
  616.     MyDisposeHandle(msg);
  617.     if (gCancel && posted) {
  618.         gCancel = false;
  619.         UncheckNewsIcon(wind);
  620.         err1 = MyGetNewDialog(kPostCancelAlert, ok, cancel, &dlg);
  621.         if (err1 != noErr) return err1;
  622.         SysBeep(0);
  623.         MyModalDialog(dlg, gDialogFilterUPP, &item);
  624.         err1 = DoClose(dlg);
  625.         if (err1 != noErr) return err1;
  626.         if (item == cancel) {
  627.             GetCString(kStrCancelingStatusMsg, statusMsg);
  628.             err1 = DisplayStatusMessage(statusMsg);
  629.             if (err1 != noErr) return err1;
  630.             err1 = CancelArticle(idStr, newsgroups, statusMsg);
  631.             if (err1 != noErr) return err1;
  632.         }
  633.     } else if (posted && mailStarted) {
  634.         UncheckNewsIcon(wind);
  635.         ReportSystemError(err);
  636.         NoteMessageNumber(kStrPostOKMailErr);
  637.         return userCanceledErr;
  638.     }
  639.     return err;
  640. }
  641.  
  642.  
  643.  
  644. /*----------------------------------------------------------------------------
  645.     SendMessageAndCloseWindow 
  646.     
  647.     Send a message and close the message window.
  648.             
  649.     Entry:    wind = pointer to message window.
  650.     
  651.     Exit:    function result = error code.
  652. ----------------------------------------------------------------------------*/
  653.  
  654. OSErr SendMessageAndCloseWindow (WindowPtr wind)
  655. {
  656.     OSErr err = noErr;
  657.  
  658.     err = SendMessage(wind);
  659.     if (err != noErr) return err;
  660.     return DoClose(wind);
  661. }
  662.